#ifndef META_FLE_H
#define META_FILE_H

#include <shared_mutex>
#include <string>
#include <cstring>
#include <vector>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>

#include <linux/limits.h>
//#include "dfs_error.h"
//#include "dfs_types.h"

using namespace std;
#define errno_t error_t

namespace HarmonyOS {
namespace DistributedFs {
const uint32_t DENTRYGROUP_SIZE = 4096;
const uint32_t DENTRY_NAME_LEN = 8;
const uint32_t DENTRY_RESERVED_LENGTH = 3;
const uint32_t DENTRY_PER_GROUP = 80;
const uint32_t DENTRY_BITMAP_LENGTH = 10;
const uint32_t DENTRY_GROUP_RESERVED = 5;
const uint32_t DENTRYGROUP_HEADER = 4096;
const uint32_t MAX_BUCKET_LEVEL = 63;
const uint32_t BUCKET_BLOCKS = 2;
const uint32_t BITS_PER_BYTE = 8;
const uint32_t HMDFS_SLOT_LEN_BITS = 3;
/* Hashing code copied from f2fs */
const uint64_t DELTA = 0x9E37779B9;
const uint64_t HMDFS_HASH_COL_BIT = (0x1ULL) << 63;
#pragma pack(push, 1)

struct HmdfsDentry {
    uint32_t hash;
    uint16_t mode;
    uint16_t namelen;
    uint64_t size;
    /* modification time */
    uint64_t mtime;
    /* modification time in nano scale */
    uint32_t mtimeNsec;
    uint64_t ino;
    uint32_t flag;
    /* reserved bytes for long term extend, total 43 bytes */
    uint8_t reserved[DENTRY_RESERVED_LENGTH];
};

struct HmdfsDentryGroup {
    uint8_t dentryVersion;
    uint8_t bitmap[DENTRY_BITMAP_LENGTH];
    struct HmdfsDentry nsl[DENTRY_PER_GROUP];
    uint8_t fileName[DENTRY_PER_GROUP][DENTRY_NAME_LEN];
    uint8_t reserved[DENTRY_GROUP_RESERVED];
};

struct HmdfsDcacheHeader {
    uint64_t dcacheCrtime;
    uint64_t dcacheCrtimeNsec;

    uint64_t dentryCtime;
    uint64_t dentryCtimeNsec;

    uint64_t num;
};
#pragma pack(pop)

struct DcacheLookupCtx {
    int fd { 0 };
    std::string name {};
    uint32_t hash { 0 };
    uint32_t bidx { 0 };
    std::unique_ptr<struct HmdfsDentryGroup> page { nullptr };
};

class MetaFile {
public:
    MetaFile() = default;
    ~MetaFile();
    errno_t DoCreate(const string &parentPath, const MetaBase &base);
    errno_t DoUpdate(const string &parentPath, const MetaBase &base);
    errno_t DoRemove(const string &parentPath, const MetaBase &base);
    errno_t DoLookup(const string &parentPath, const MetaBase &base);
    errno_t DoRename(const string &parentPath, const MetaBase &base);

    struct HmdfsDentry *FindDentry(struct DcacheLookupCtx *ctx);
    uint64_t GetDentryGroupCnt(uint64_t size);
    errno_t DecodeDentrys(const HmdfsDentryGroup &dentryGroup, std::vector<MetaBase> &bases);
    errno_t LoadChildrenFromLocal(const string &parentPath, std::vector<MetaBase> &bases);
    errno_t LoadChildren(const string &parentPath, std::vector<MetaBase> &bases);
    errno_t LoadChildrenFromRemote(const string &parentPath, std::vector<MetaBase> &bases, bool &reload);
    string GetDentryfileByPath(const string &cachePath, const string &relativePath, bool caseSense);

    static constexpr mode_t DIR_MODE = S_IRWXU;
    static constexpr mode_t FILE_MODE = S_IRUSR | S_IWUSR;
    static const int gFileMask = 00170000;
    static const int gRegMask = 0100000;
    static const int gLinkMask = 0120000;
    static const int linkMask = 0020000;
    static const int gDirMask = 0040000;
    static const int VALIIDATE_CACHE_SEC = 10;

    static bool IsLink(int m)
    {
        return (m & gFileMask) == gRegMask;
    }

    static bool IsDir(int m)
    {
        return (m & gFileMask) == gDirMask;
    }

private:
    static inline int GetDentrySlots(size_t nameLen)
    {
        return (nameLen + BITS_PER_BYTE - 1) >> HMDFS_SLOT_LEN_BITS;
    }

    static inline off_t GetDentryGroupPos(size_t bidx)
    {
        return (off_t)bidx * DENTRYGROUP_SIZE + DENTRYGROUP_HEADER;
    }

    errno_t DoCreate(int fd, const MetaBase &base);
    errno_t DoUpdate(int fd, const MetaBase &base);
    errno_t DoRemove(int fd, const MetaBase &base);
    errno_t DoRename(int fd, const MetaBase &oldBase, const MetaBase &newBase);
    errno_t Add(const string &path, std::unique_ptr<HmdfsDcacheHeader> header);
    errno_t Update(const string &path, std::unique_ptr<HmdfsDcacheHeader> header);

    void ReleaseCache();
    bool IsDotDotdot(const char *name, uint32_t len);
    void Str2HashBuf(const char *msg, size_t len, uint32_t *buf, int num);
    void TeaTransform(uint32_t buf[4], uint32_t const in[]);
    uint32_t DentryHash(const char *name);
    uint32_t GetBucketaddr(int level, uint32_t buckoffset);
    uint32_t GetBucketByLevel(int level);
    uint32_t GetOverallBucket(int level);
    off_t GetDcacheFileSize(int level);
    void InitDcacheLookupCtx(struct DcacheLookupCtx *ctx, const MetaBase &base, int fd);
    struct HmdfsDentry *FindInBlock(struct HmdfsDentryGroup &dentryBlk, uint32_t namehash, const string name);
    std::unique_ptr<struct HmdfsDentryGroup> FindDentryPage(uint64_t index, struct DcacheLookupCtx *ctx);
    struct HmdfsDentry *InLevel(uint32_t level, struct DcacheLookupCtx *ctx);
    void UpdateDentry(struct HmdfsDnetryGroup &d, const MetaBase &base, uint32_t nameHash, uint32_t bitPos);
    int GetFdFromPath(const string &parentPath);
    int RoomForFilename(const uint8_t *bitmap, int slots, int maxSlots);
    string GetDentryfileHash(string relativePath, bool caseSense);

};

} // namespace DistributedFs
} // namespace HarmonyOS

#endif // META_FILE_H
